home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / games / IndiZone / blix / blixtrackball.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  6.0 KB  |  233 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*__________________________________________________________________________
  18.  |
  19.  | blixtrackball.c - virtual trackball 
  20.  |
  21.  |  based on the implemantation of Gavin Bell, but adapted to meet blix
  22.  |  high standards :-)
  23.  |
  24.  |    Implementation of a virtual trackball.
  25.  |    Implemented by Gavin Bell, lots of ideas from Thant Tessman and
  26.  |        the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
  27.  |
  28. */
  29.  
  30. #include "blixtrackball.h"
  31. #include "config.h"
  32.  
  33. float trackballsize = 0.8;
  34. float trackballpos = 0;
  35.  
  36. void set_trackball(const float t, const float ypos) {
  37.  
  38.         trackballsize = t;
  39.     trackballpos = ypos;
  40. }
  41.  
  42. /*
  43.  * Local function prototypes (not defined in trackball.h)
  44.  */
  45. float tb_project_to_sphere(const float, const float, const float);
  46. static void normalize_quat(float [4]);
  47.  
  48. /*
  49.  * a few constants from math.h, so this compiles as ansi code too
  50.  */
  51.  
  52. #ifndef M_SQRT2
  53. #  define M_SQRT2         1.41421356237309504880
  54. #endif
  55. #ifndef M_SQRT1_2
  56. #  define M_SQRT1_2       0.70710678118654752440
  57. #endif
  58.  
  59. /*
  60.  * Ok, simulate a track-ball.  Project the points onto the virtual
  61.  * trackball, then figure out the axis of rotation, which is the cross
  62.  * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
  63.  * Note:  This is a deformed trackball-- is a trackball in the center,
  64.  * but is deformed into a hyperbolic sheet of rotation away from the
  65.  * center.  This particular function was chosen after trying out
  66.  * several variations.
  67.  * 
  68.  * It is assumed that the arguments to this routine are in the range
  69.  * (-1.0 ... 1.0)
  70.  */
  71. void trackball(float q[4], const float p1x, const float p1y,
  72.         const float p2x, const float p2y) {
  73.     float a[3];    /* Axis of rotation */
  74.     float phi;    /* how much to rotate about axis */
  75.     float p1[3], p2[3], d[3];
  76.     float t;
  77.  
  78.     if (p1x == p2x && p1y == p2y)
  79.     {
  80.         vzero(q); q[3] = 1.0; /* Zero rotation */
  81.         return;
  82.     }
  83.  
  84. /*
  85.  * First, figure out z-coordinates for projection of P1 and P2 to
  86.  * deformed sphere
  87.  */
  88.     vset(p1,p1x,p1y,tb_project_to_sphere(trackballsize,p1x,
  89.         p1y - trackballpos));
  90.     vset(p2,p2x,p2y,tb_project_to_sphere(trackballsize,p2x,
  91.         p2y - trackballpos));
  92.  
  93. /*
  94.  *    Now, we want the cross product of P1 and P2
  95.  */
  96.     vcross(p2,p1,a);
  97.  
  98. /*
  99.  *    Figure out how much to rotate around that axis.
  100.  */
  101.     vsub(p1,p2,d);
  102.     t = vlength(d) / (2.0*trackballsize);
  103.     /*
  104.      * Avoid problems with out-of-control values...
  105.      */
  106.     if (t > 1.0) t = 1.0;
  107.     if (t < -1.0) t = -1.0;
  108.     phi = 2.0 * asin(t);
  109.  
  110.     axis_to_quat(a,phi,q);
  111. }
  112.  
  113. /*
  114.  *    Given an axis and angle, compute quaternion.
  115.  */
  116. void axis_to_quat(float a[3], const float phi, float q[4]) {
  117.     vnormal(a);
  118.     vcopy(a, q);
  119.     vscalar( q, sinf(phi/2.0));
  120.     q[3] = cosf(phi/2.0);
  121. }
  122.  
  123. /*
  124.  * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
  125.  * if we are away from the center of the sphere.
  126.  */
  127. float tb_project_to_sphere(const float r, const float x,
  128.         const float y) {
  129.     float d, t, z;
  130.  
  131.     d = sqrtf(x*x + y*y);
  132.     if (d < r * 0.95) {     /* Inside sphere */
  133.         z = sqrtf(r*r - d*d);
  134.     } else {         /* On hyperbola */
  135.         t = r * 0.544644 ;
  136.         z = t*t / d ;
  137.     }
  138.     return z;
  139. }
  140.  
  141. /*
  142.  * Given two rotations, e1 and e2, expressed as quaternion rotations,
  143.  * figure out the equivalent single rotation and stuff it into dest.
  144.  * 
  145.  * This routine also normalizes the result every RENORMCOUNT times it is
  146.  * called, to keep error from creeping in.
  147.  *
  148.  * NOTE: This routine is written so that q1 or q2 may be the same
  149.  * as dest (or each other).
  150.  */
  151.  
  152. #define RENORMCOUNT 97
  153.  
  154. void add_quats(const float q1[4], const float q2[4], float dest[4]) {
  155.     static int count=0;
  156.     float t3[3];
  157.     float q13, q23;
  158.     
  159.     vcross(q2, q1, t3);
  160.     q23 = q2[3];
  161.     q13 = q1[3];
  162.     dest[3] = q13 * q23 - vdot(q1,q2);
  163.     dest[0] = q1[0]*q23 + q2[0]*q13 + t3[0];
  164.     dest[1] = q1[1]*q23 + q2[1]*q13 + t3[1];
  165.     dest[2] = q1[2]*q23 + q2[2]*q13 + t3[2];
  166.     /*
  167.     vcopy(q1,t1); 
  168.     vcopy(q2,t2); 
  169.     vcross(t2,t1,t3);
  170.     vscalar(t1,q2[3]);
  171.     vscalar(t2,q1[3]);
  172.     vadd(t1,t2,tf);
  173.     vadd(t3,tf,tf);
  174.     tf[3] = q1[3] * q2[3] - vdot(q1,q2);
  175.  
  176.     dest[0] = tf[0];
  177.     dest[1] = tf[1];
  178.     dest[2] = tf[2];
  179.     dest[3] = tf[3];
  180.     */
  181.     if (++count > RENORMCOUNT)
  182.     {
  183.         count = 0;
  184.         normalize_quat(dest);
  185.     }
  186. }
  187.  
  188. /*
  189.  * Quaternions always obey:  a^2 + b^2 + c^2 + d^2 = 1.0
  190.  * If they don't add up to 1.0, dividing by their magnitued will
  191.  * renormalize them.
  192.  *
  193.  * Note: See the following for more information on quaternions:
  194.  * 
  195.  * - Shoemake, K., Animating rotation with quaternion curves, Computer
  196.  *   Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
  197.  * - Pletinckx, D., Quaternion calculus as a basic tool in computer
  198.  *   graphics, The Visual Computer 5, 2-13, 1989.
  199.  */
  200. static void normalize_quat(float q[4]) {
  201.     int i;
  202.     float mag;
  203.  
  204.     mag = (q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
  205.     for (i = 0; i < 4; i++) q[i] /= mag;
  206. }
  207.  
  208. /*
  209.  * Build a rotation matrix, given a quaternion rotation.
  210.  *
  211.  */
  212. void build_rotmatrix(Matrix m, const float q[4]) {
  213.     m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
  214.     m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
  215.     m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
  216.     m[0][3] = 0.0;
  217.  
  218.     m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
  219.     m[1][1] = 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
  220.     m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
  221.     m[1][3] = 0.0;
  222.  
  223.     m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
  224.     m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
  225.     m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
  226.     m[2][3] = 0.0;
  227.  
  228.     m[3][0] = 0.0;
  229.     m[3][1] = 0.0;
  230.     m[3][2] = 0.0;
  231.     m[3][3] = 1.0;
  232. }
  233.